package com.t.bricks.bussiness.component.lucene;

import java.util.List;
import java.util.Map;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import com.t.bricks.bussiness.util.lucene.LuceneFactory;
import com.t.bricks.model.Log;
import com.t.bricks.model.MsgEmity;
import com.t.bricks.model.OrderInfoList;
import com.t.bricks.utils.function.reflect.ReflectUtil;
import com.t.bricks.utils.spring.ModuleUtil;
import com.t.bricks.utils.spring.SpringContextUtil;

/**
 * 搜索引擎切面子类,专门处理新增数据时的关联操作
 */
@Component
@Aspect
public class LuceneAspectAdd extends LuceneAspectBase {

	/**
	 * 定义切入点，切入点为'MsgEmity com.t.bricks.bussiness.db.dao.*.impl.*DaoImpl.add(..)'下的add函数,并且函数可以有未定多的参数,若监听参数明确个数则用多个*代表参数(用?会异常)
	 */
	@Pointcut(value = "execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.*.impl..*DaoImpl.add(..))")
	//@Pointcut(value = "execution(* com.t.bricks.bussiness.db.dao.*.impl..*DaoImpl.*(..))")
	@Override
	public void doLuceneAspect() {
	}
    
	/**
	 * 后置/返回值增强
     * @param joinPoint
     * @param result 被切点方法执行后的返回值
     * @return
	 */
	@AfterReturning(returning="result", pointcut="doLuceneAspect()")
	public void afterReturning(JoinPoint joinPoint, Object result) {
		if (!isCanAop) {
			return;//不进行搜索引擎切面操作,退出
		}
		
		if (!(result instanceof MsgEmity)) {//不是返回MsgEmity,则说明已经改变
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			String methodName = signature.getMethod().getName();
			Log.error("方法'", methodName, "'返回数据不是MsgEmity");
			return;
		}

		MsgEmity me = (MsgEmity)result;
		if (!me.isSuccess()) {
			return;//原方法执行失败,不处理
		}
		
		add(joinPoint, me);//多线程处理
	}

	/**
	 * 环绕通知
	 * @param joinPoint
	 * @return
	 * @throws Throwable
	 */
	@Around("doLuceneAspect()")
	@Override
	public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
		return joinPoint.proceed();//执行原切面中的预定方法后返回内容
	}
	
	/**
	 * 添加数据
	 * @param joinPoint
	 * @param msgEmity
	 */
	private void add(JoinPoint joinPoint, MsgEmity msgEmity) {
		Object entity = msgEmity.getData();//执行了DAO的add方法后,返回的实体对象
		
		if (null == entity) {
			return;//不处理
		}
		
		if ((entity instanceof Integer) || (entity instanceof String)) {
			return;//不符合结构的数据不需要进行
		}

		JoinPoint FjoinPoint = joinPoint;
		
		ModuleUtil.runThread(() -> {//多线程方式重新构造缓存数据
			crateLuceneCore(FjoinPoint, sLuceneIndexPath);//建立搜索库,不论是否成功都往下走
			
			Map<String, String> map = getKeyInfo(entity);
			if (map == null) {
				Log.error("无法获取", entity.getClass().getSimpleName(), "新增后的id值,请检查数据库的主键名称是否符合,同时脚本语句是否获取了新数据对应的id!");
				return;
			}
			
			String idName = map.get("idName");
			String idObj = map.get("idObj");
			
			Class<?> clazz = getGenericClass(msgEmity);
			
			if ("/String/Integer/int/".contains(clazz.getSimpleName())) {
				return;//不符合的要求,否则会出现" where Integer.iId= "的异常执行语句
			}
			
			String whereStr = new StringBuilder()//表名前不能加"[dbo]."，否则sql会报错
				.append(clazz.getSimpleName())
				.append(".").append(idName).append(" = ")
				.append(("sId".equals(idName) || "uId".equals(idName)) ? "'" : "")
				.append(idObj)
				.append(("sId".equals(idName) || "uId".equals(idName)) ? "'" : "")
				.toString();
			
			String beanName = getDaoBeanName(joinPoint);

			MsgEmity me = null;
			
			Object bean = SpringContextUtil.getBean(beanName);
			if (ReflectUtil.hasMethod("findBySearch", bean, String.class, OrderInfoList.class, Class.class)) {
				me = SpringContextUtil.doMethod(
						beanName, "findBySearch",
						new Class<?>[]{ String.class, OrderInfoList.class, Class.class },
						new Object[]{ whereStr, null, entity.getClass() });
			} else {
				me = SpringContextUtil.doMethod(
						beanName, "findBySearch",
						new Class<?>[]{ String.class, OrderInfoList.class },
						new Object[]{ whereStr, null });
			}
				
			if (null == me || !me.isSuccess()) {
				Log.error("搜索引擎读取数据失败!");
				return;
			}
			
			me = me.getData();//SpringContextUtil.doMethod返回的data里面是MsgEmity
			if (!me.isSuccess()) {
				Log.error("Dao'", beanName, "'读取数据失败!");
				return;
			}
			
			List<?> list = me.getData();
			if (list.size() < 1) {
				return;
			}

			LuceneFactory.add(idName, list.get(0), getCore(joinPoint, sLuceneIndexPath));
		});
	}

}
